﻿using MCUPackage;
using MCUPackage.DesignEditor;
using MCUPackage.Utils;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Linq;
using System.Text;

namespace SxPackages.STC32G.Models
{
	/// <summary>
	/// 串口设置基类
	/// </summary>
	[Serializable]
	class USARTOptionBase
	{
		protected STC32GQFP64 mParent = null;

		/// <summary>
		/// 串口序号
		/// </summary>
		[Browsable(false)]
		[JsonIgnore]
		public int Id { get; protected set; }
		/// <summary>
		/// 使用的引脚名结合
		/// </summary>
		protected string[] mUsePins { get; set; }
		protected virtual void SetPins(string[] aPins)
		{

		}

		/// <summary>
		/// 切换引脚
		/// </summary>
		/// <param name="aNew"></param>
		/// <param name="aOld"></param>
		/// <returns>是否切换成功</returns>
		protected bool SwitchPins<T>(T aNew, T aOld)
		{
			string[] newPins = TemplateHelper.GetPins(aNew);
			string[] oldPins = TemplateHelper.GetPins(aOld);

			if (this.Enable)
			{
				if (mParent.PinIsUsedTips(newPins))
				{
					return false;
				}
				SetPins(newPins);
				// 清除占用的功能脚
				mParent.ResetPins(oldPins);
			}

			mUsePins = newPins;
			return true;
		}

		private bool mEnable = false;
		[DisplayName("使能"),
		DefaultValue(false),
		JsonProperty(Order = 100),
		Description("是否使能本串口"),
		PropertyOrder(0)]
		public virtual bool Enable
		{
			get => mEnable;
			set
			{
				if (value != mEnable)
				{
					if (value)
					{
						if (TimeIsUsed(this.Timer))
						{
							GuiUtils.MsgBox($"定时器{(int)this.Timer}已经启用, 无法被用于本串口波特率发生器.");
							return;
						}
						if (mParent.PinIsUsedTips(mUsePins))
						{
							return;
						}
						if (BaudIsDiff(Timer, BaudRate))
						{
							return;
						}
						// 设置引脚用途
						SetPins(mUsePins);
					}
					else
					{
						// 清除占用的功能脚
						mParent.ResetPins(mUsePins);
					}

					mEnable = value;
				}
			}
		}

		private USARTMode mMode = USARTMode.可变波特率8位数据方式;
		[DisplayName("工作模式"),
		DefaultValue(USARTMode.可变波特率8位数据方式),
		Description("本串口的工作模式, 串口1与串口2可工作在同步移位与固定波特率9位数据方式")]
		public USARTMode Mode
		{
			get => mMode;
			set
			{
				if (value != mMode)
				{
					if (Id > 2)
					{
						if (value == USARTMode.同步移位方式 || value == USARTMode.固定波特率9位数据方式)
						{
							// 串口3, 4不支持以上两种方式
							return;
						}
					}
					if (value == USARTMode.同步移位方式 || value == USARTMode.可变波特率8位数据方式)
					{
						EnableMult = false;
					}
					mMode = value;
				}
			}
		}

		/// <summary>
		/// 判断指定的定时器是否被占用
		/// </summary>
		/// <param name="aTimer"></param>
		/// <returns></returns>
		private bool TimeIsUsed(UartTimer aTimer)
		{
			if (mParent.Tmrs == null)
			{
				return false;
			}
			var tmrs = mParent.mTmrs.All;
			foreach (var tmr in tmrs)
			{
				if ((int)aTimer == tmr.Id && tmr.Enable)
				{
					return true;
				}
			}

			return false;
		}

		private UartTimer mTimer = UartTimer.Timer2;
		[DisplayName("时钟源"),
		DefaultValue(UartTimer.Timer2),
		Description("本串口波特率发生器需要使用的时钟源")]
		public UartTimer Timer
		{
			get => mTimer;
			set
			{
				if (value != mTimer)
				{
					if (Enable)
					{
						if (value != UartTimer.Timer2 && (int)value != Id)
						{
							GuiUtils.MsgBox($"串口{Id}只能使用定时器{Id}与定时器2!");
							return;
						}
						if (TimeIsUsed(value))
						{
							GuiUtils.MsgBox($"定时器{(int)value}已经启用, 无法被用于本串口波特率发生器.");
							return;
						}
						if (BaudIsDiff(value, BaudRate))
						{
							// 确保定时器2波特率设置一致
							return;
						}
					}

					mTimer = value;
				}
			}
		}

		/// <summary>
		/// 对波特率进行检验
		/// </summary>
		/// <param name="aBaud"></param>
		/// <returns></returns>
		private bool BaudIsDiff(UartTimer aTmr, int aBaud)
		{
			if (aTmr != UartTimer.Timer2)
			{
				return false;
			}
			// 检查其他使用定时器2的波特率是否相同
			USARTOptionBase[] opts = mParent.mUarts.All;
			for (int i = 0; i < opts.Length; i++)
			{
				if (Id != opts[i].Id && opts[i].Enable && opts[i].Timer == UartTimer.Timer2)
				{
					if (aBaud != opts[i].BaudRate)
					{
						GuiUtils.MsgBox($"定时器2已经被串口{opts[i].Id}使用产生了{opts[i].BaudRate}波特率, 本串口如需使用定时器2请保持波特率一致!");
						return true;
					}
				}
			}

			return false;
		}

		private int mBaudRate = 9600;
		[DisplayName("波特率"),
		DefaultValue(9600),
		Description("串口波特率设置, 1200~115200"),
		TypeConverter(typeof(IntCollectionConvertor)),
		IntCollection(new int[] { 1200, 2400, 4800, 9600, 14400, 19200, 28800, 38400, 57600, 115200 })]
		public int BaudRate
		{
			get => mBaudRate;
			set
			{
				if (value != mBaudRate)
				{
					if (Enable)
					{
						if (BaudIsDiff(Timer, value))
						{
							return;
						}
					}
					mBaudRate = value;
				}
			}
		}

		[DisplayName("接收使能"),
		DefaultValue(true),
		Description("是否使能串口的接收功能")]
		public bool EnableRcv { get; set; } = true;

		private bool mEnableMult = false;
		[DisplayName("使能多机通信"),
		DefaultValue(false),
		Description("是否使能串口的多机通信功能, 工作在模式为波特率9位时可以使能")]
		public bool EnableMult
		{
			get => mEnableMult;
			set
			{
				if (value != mEnableMult)
				{
					if (value && (Mode == USARTMode.同步移位方式 || Mode == USARTMode.可变波特率8位数据方式))
					{
						return;
					}
				}

				mEnableMult = value;
			}
		}

		[DisplayName("中断使能"),
		DefaultValue(true),
		Description("是否使能串口中断")]
		public bool EnableTI { get; set; } = true;

		[DisplayName("中断优先级"),
		Description("中断优先级等级设置"),
		DefaultValue(PriorityTypes.最低级)]
		public PriorityTypes Priority { get; set; } = PriorityTypes.最低级;

		[DisplayName("DMA接收使能"),
		DefaultValue(false),
		Description("是否使能本串口的DMA接收功能")]
		public bool EnableDMARcv { get; set; } = false;

		private int mRcvLength = 256;
		[DisplayName("DMA接收上限"),
		DefaultValue(256),
		Description("DMA接收数据缓冲区的大小, 取值范围1~65536, 不要超过芯片xdata区域的上限")]
		public int RcvLength
		{
			get => mRcvLength;
			set
			{
				if (value != mRcvLength)
				{
					if (value < 1 || value > 65536)
					{
						return;
					}
					mRcvLength = value;
				}
			}
		}

		[DisplayName("DMA发送使能"),
		DefaultValue(false),
		Description("是否使能本串口的DMA发送功能")]
		public bool EnableDMASnd { get; set; }

		private int mSndLength = 256;
		[DisplayName("DMA发送上限"),
		DefaultValue(256),
		Description("DMA数据发送缓冲区的大小, 取值范围1~65536, 不要超过芯片xdata区域的上限")]
		public int SndLength
		{
			get => mSndLength;
			set
			{
				if (value != mSndLength)
				{
					if (value < 1 || value > 65536)
					{
						return;
					}
					mSndLength = value;
				}
			}
		}

		[DisplayName("DMA中断优先级"),
		Description("DMA中断优先级等级设置"),
		DefaultValue(PriorityTypes.最低级)]
		public PriorityTypes DMAPriority { get; set; } = PriorityTypes.最低级;

		[DisplayName("总线优先级"),
		Description("DMA数据总线访问优先级等级设置"),
		DefaultValue(PriorityTypes.最低级)]
		public PriorityTypes BusPriority { get; set; } = PriorityTypes.最低级;

		public USARTOptionBase(STC32GQFP64 aParent)
		{
			this.mParent = aParent;
		}

		public override String ToString()
		{
			return string.Empty;
		}

		/// <summary>
		/// 初始化模板
		/// </summary>
		private const string TEMPLATE =
@"	attr.UART_Mode      = {0};	//模式, UART_ShiftRight,UART_8bit_BRTx,UART_9bit,UART_9bit_BRTx
	attr.UART_BRT_Use   = BRT_Timer{1};			//选择波特率发生器 (注意: 串口2固定使用BRT_Timer2)
	attr.UART_BaudRate  = {2}ul;			//波特率, 一般 110 ~ 115200
	attr.UART_RxEnable  = {3};				//接收允许,   ENABLE或DISABLE
	attr.BaudRateDouble = {4};			//波特率加倍, ENABLE或DISABLE
	UART_Configuration(UART{5}, &attr);		//初始化串口1 UART1,UART2,UART3,UART4
	NVIC_UART{5}_Init({6}, {7});		//中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0,Priority_1,Priority_2,Priority_3
	UART{5}_SW(UART{5}_SW{8});";

		/// <summary>
		/// DMA初始化模板
		/// </summary>
		private const string DMA_TEMPLATE =
@"	dma.DMA_TX_Length = (uint16_t){0};				//DMA传输总字节数  	(0~65535) + 1
	dma.DMA_TX_Buffer = (uint16_t){1};	//发送数据存储地址
	dma.DMA_RX_Length = (uint16_t){2};				//DMA传输总字节数  	(0~65535) + 1
	dma.DMA_RX_Buffer = (uint16_t){3};	//接收数据存储地址
	dma.DMA_TX_Enable = {4};		//DMA使能  	ENABLE,DISABLE
	dma.DMA_RX_Enable = {5};		//DMA使能  	ENABLE,DISABLE
	DMA_UART_Inilize(UART{6}, &dma);	//初始化
	NVIC_DMA_UART{6}_Tx_Init({4}, {7}, {8});		//中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0~Priority_3; 总线优先级(低到高) Priority_0~Priority_3
	NVIC_DMA_UART{6}_Rx_Init({5}, {7}, {8});		//中断使能, ENABLE/DISABLE; 优先级(低到高) Priority_0~Priority_3; 总线优先级(低到高) Priority_0~Priority_3
	DMA_UR{6}R_CLRFIFO();		//清空 DMA FIFO";

		/// <summary>
		/// 变量模板
		/// </summary>
		private const string RCV_VAR_TEMPLATE =
@"#define UART{0}_RCVDMA_MAX		{1}
uint8_t xdata UART{0}_RcvDMA_Buffer[UART{0}_RCVDMA_MAX];";

		private const string SND_VAR_TEMPLATE =
@"#define UART{0}_SNDDMA_MAX		{1}
uint8_t xdata UART{0}_SndDMA_Buffer[UART{0}_SNDDMA_MAX];";

		public string[] Generate(Dictionary<string, List<string>> aLst)
		{
			if (!this.Enable)
			{
				return null;
			}

			StringBuilder funcSb = new StringBuilder();
			StringBuilder varSb = new StringBuilder();
			string pins = string.Empty;
			foreach (var pin in mUsePins)
			{
				var opt = mParent.GetPinOption(pin);
				if (opt != null)
				{
					opt.ToDictionary(aLst);
					pins += "_";
					pins += pin.Replace(".", "");
				}
			}

			funcSb.AppendFormat(TEMPLATE, this.Mode.ToDescription(), (int)this.Timer, this.BaudRate,
								this.EnableRcv.ToEnable(), false.ToEnable(), this.Id,
								this.EnableTI.ToEnable(), this.Priority.ToDescription(), pins);
			funcSb.AppendLine();

			if (this.EnableDMARcv || this.EnableDMASnd)
			{
				string rcvName = "NULL", sndName = "NULL";
				string rcvLength = "0", sndLength = "0";
				if (this.EnableDMARcv)
				{
					varSb.AppendFormat(RCV_VAR_TEMPLATE, this.Id, this.RcvLength).AppendLine();
					rcvName = $"UART{this.Id}_RcvDMA_Buffer";
					rcvLength = $"(UART{this.Id}_RCVDMA_MAX - 1)";
				}
				if (this.EnableDMASnd)
				{
					varSb.AppendFormat(SND_VAR_TEMPLATE, this.Id, this.SndLength).AppendLine();
					sndName = $"UART{this.Id}_SndDMA_Buffer";
					sndLength = $"(UART{this.Id}_SNDDMA_MAX - 1)";
				}
				funcSb.AppendLine();
				funcSb.AppendFormat(DMA_TEMPLATE, sndLength, sndName, rcvLength, rcvName,
									this.EnableDMASnd.ToEnable(), this.EnableDMARcv.ToEnable(), this.Id,
									this.DMAPriority.ToDescription(), this.BusPriority.ToDescription());
				funcSb.AppendLine();
			}

			return new string[] { funcSb.ToString(), varSb.ToString() };
		}
	}
}
